﻿Imports System.Net.Sockets
Imports System.Text

Public Class frmChatroom
    Private recipientName As String = ""
    Private recipientIP As String = ""
    Private chatTcpClient As TcpClient
    Private alChatterIPs As ArrayList
    Private alSockets As ArrayList
    Private chatroomId As String ' all messages frm & to this windows will contain this id
    Private mpRecipients As Hashtable ' recipientIP|recipientName values
    Private chatPort As Integer = frmMain.chatroomPort
    Delegate Sub UpdateChatLogCallback(ByVal strMessage As String, ByVal personName As String)


    Public Sub New(ByRef chatTcpClnt As TcpClient, ByVal strRecName As String, ByVal strRecIP As String, ByRef alchatters As ArrayList, ByVal chatrmId As String)
        InitializeComponent()
        Me.recipientIP = strRecIP
        Me.recipientName = strRecName
        Me.chatTcpClient = chatTcpClnt
        Me.chatroomId = chatrmId
        Me.alChatterIPs = alchatters
    End Sub

    ' reduce the count of windows using the sockets. In frmMain, it will check if
    ' anybody at all is using the socket being closed. If no one is using it,
    ' it will close that socket.
    Private Sub frmChatroom_FormClosing(ByVal sender As System.Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles MyBase.FormClosing
        Dim chatterIP As String

        For Each chatterIP In Me.alChatterIPs
            Try
                frmMain.updateSocketUserCount(chatterIP, "DEC")
            Catch ex As Exception
                MessageBox.Show("exception: " & ex.ToString)
            End Try
        Next
    End Sub

    Private Sub frmChatroom_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        txtMsg.Focus()
    End Sub

    ' connection with chatroom initiator is already established.
    ' Now connect with remaining chatters
    Private Sub connectToAllChatters()
        Dim chatterIP As String
        Dim tcpClnt As TcpClient

        alSockets = New ArrayList()
        alSockets.Add(Me.chatTcpClient)
        For Each chatterIP In alChatterIPs
            If Not chatterIP.Equals(Me.recipientIP) Then
                If Not frmMain.mapOfChatroomSockets.ContainsKey(chatterIP) Then
                    ' connect to chatter on chatroom socket 
                    tcpClnt = New TcpClient(chatterIP, chatPort)
                    ' add this open socket to the map maintained in frmMain to
                    ' avoid creation of duplicate socket on further requests
                    frmMain.mapOfChatroomSockets.Add(chatterIP, tcpClnt)
                Else
                    tcpClnt = frmMain.mapOfChatroomSockets.Item(chatterIP)
                End If
                updateChatterList(mpRecipients.Item(chatterIP), "ADD")
                frmMain.updateSocketUserCount(chatterIP, "INC")
            End If
            ' once socket is obtained, add it to list of sockets for this chatroom
            alSockets.Add(tcpClnt)
            ' show this chatter in this chatroom
            updateChatterList(mpRecipients.Item(Me.recipientIP), "ADD")
            ' update the count of chatrooms using this socket
            frmMain.updateSocketUserCount(Me.recipientIP, "INC")
        Next
    End Sub

    'append text to chat log window
    Public Sub updateMessageLog(ByVal strMessage As String, ByVal personName As String)
        If txtChatlog.InvokeRequired Then
            Dim d As New UpdateChatLogCallback(AddressOf updateMessageLog)
            Me.Invoke(d, New Object() {strMessage, personName})
        Else
            If Not txtChatlog.IsDisposed Then
                Dim currentTextLength = txtChatlog.TextLength
                txtChatlog.AppendText(strMessage + Environment.NewLine)
                txtChatlog.SelectionStart = currentTextLength
                txtChatlog.SelectionLength = (personName & " says:").Length
                If personName.Equals(My.Settings.displayName) Then
                    txtChatlog.SelectionColor = Color.Blue
                Else
                    txtChatlog.SelectionColor = Color.Crimson
                End If

                txtChatlog.SelectionFont = New Font(txtChatlog.SelectionFont, FontStyle.Bold)
                txtChatlog.SelectionLength = 0
                txtChatlog.ScrollToCaret()
            End If
        End If
    End Sub

    Private Sub txtMsg_KeyUp(ByVal sender As System.Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles txtMsg.KeyUp
        If e.KeyCode = Keys.Enter Then
            btnSend_Click(sender, e)
        End If
    End Sub

    Private Sub btnSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSend.Click
        If (txtMsg.Text.Trim.Length > 0) Then
            sendText()
            txtMsg.Text = ""
            txtMsg.Focus()
        End If
    End Sub

    Private Sub sendText()
        Dim messageToSend As String = My.Settings.displayName & " says: " & txtMsg.Text.Trim()
        Dim sendBytes As [Byte]() = Encoding.ASCII.GetBytes(messageToSend)
        Dim sock As TcpClient

        For Each sock In alSockets
            Try
                sock.GetStream().Write(sendBytes, 0, sendBytes.Length)
            Catch ex As Exception
                MessageBox.Show("Exception Occured!" & vbCrLf & ex.ToString)
            End Try
        Next
        updateMessageLog(messageToSend, My.Settings.displayName)
        txtMsg.Text = ""
    End Sub

    'update the list of online/offline chatters
    Private Sub updateChatterList(ByVal operation As String, ByVal strValue As String)
        If lstChatters.InvokeRequired Then
            Dim d As New UpdateChatLogCallback(AddressOf updateChatterList)
            Me.Invoke(d, New Object() {operation, strValue})
        Else
            If operation.Equals("ADD") Then
                lstChatters.Items.Add(strValue)
            ElseIf operation.Equals("REMOVE") Then
                lstChatters.Items.Remove(strValue)
            End If
        End If
    End Sub
End Class